
package todolist.storage;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import todolist.logic.parser.PriorityParser;
import todolist.personalization.ErrorMessages;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;

/**
 * Reads Task List file using XMLParser/DOM. Singleton class.
 * @author YouLi
 * @author Ivan (10%)
 */
public class Import {

	// handle singleton instance

	private static Import _objImport;

	public static Import getInstance() {
		if (_objImport == null)
			_objImport = new Import();
		return _objImport;
	}
	
	// member attributes
	
	private ArrayList<DocumentDeletedListener> _objDDList; // listener
	private ArrayList<TaskImportedListener> _objTIList; // listener
	
	private static final String IMPORT_FILE = "toDoList.xml";
	
	private Import() {
		_objDDList = new ArrayList<DocumentDeletedListener>();
		_objTIList = new ArrayList<TaskImportedListener>();
	}
	
	// listener methods
	
	public void addDocumentDeletedListener(DocumentDeletedListener pobjDDListener) {
		_objDDList.add(pobjDDListener);
	}
	
	public boolean removeDocumentDeletedListener(DocumentDeletedListener pobjDDListener) {
		return _objDDList.remove(pobjDDListener);
	}
	
	public void addTaskImportedListener(TaskImportedListener pobjTIListener) {
		_objTIList.add(pobjTIListener);
	}
	
	public boolean removeTaskImportedListener(TaskImportedListener pobjTIListener) {
		return _objTIList.remove(pobjTIListener);
	}
	
	// importer methods

	/**
	 * Imports Task from file.
	 * Notifies all observers to handle the File Deletion cleanup and each Task Creation.
	 * Any error is graphically displayed here.
	 */
	public void importTaskEntities() {
		try {
			// read document to DOM
			File objFile = new File(IMPORT_FILE);
			DocumentBuilder objDocBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document objDoc = objDocBuilder.parse(objFile);
			objDoc.getDocumentElement().normalize();
			// gather Tasks details
			NodeList objNodeList = objDoc.getChildNodes().item(0).getChildNodes(); // list of task nodes
			ArrayList<String[]> objDetailsList = new ArrayList<String[]>();
			for (Node objCurrNode = objNodeList.item(0);
				objCurrNode != null;
				objCurrNode = objCurrNode.getNextSibling()) { // traverse all nodes
				if (objCurrNode.getNodeType() != Node.ELEMENT_NODE)
					continue;
				// consider only elements
				Element objElement = (Element) objCurrNode;
				String[] arrDetails = new String[5];
				arrDetails[0] = getTagValue("taskName", objElement);
				arrDetails[1] = getTagValue("taskDate", objElement);
				arrDetails[2] = getTagValue("taskPriority", objElement);
				arrDetails[3] = getTagValue("taskReminderOffSet", objElement);
				arrDetails[4] = getTagValue("taskComment", objElement);
				objDetailsList.add(arrDetails);
				// TODO : v0.x - Status unimplemented
			}
			// delete and recreate file to preserve integrity and defragment data
			objFile.delete();
			for (DocumentDeletedListener objDDListener : _objDDList) // notify deletion
				objDDListener.documentDeleted();
			PriorityParser objPriorityParser = new PriorityParser();
			for (String[] arrDetails : objDetailsList)
				for (TaskImportedListener objTIListener : _objTIList) // notify recreation of each task
					objTIListener.importTaskFromFile(
						arrDetails[0],
						arrDetails[1],
						objPriorityParser.parsePriority(arrDetails[2]),
						Integer.parseInt(arrDetails[3]),
						arrDetails[4]
						// TODO : v0.x - Status unimplemented
					);
		} catch (FileNotFoundException objEx) {
			JOptionPane.showMessageDialog(null,
				ErrorMessages.ERR_IMPORT_FILE_NOT_FOUND,
		    	"Import Failed", JOptionPane.WARNING_MESSAGE, null);
		} catch (Exception objEx) {
			JOptionPane.showMessageDialog(null,
				ErrorMessages.ERR_IMPORT_FAILED,
		    	"Import Failed", JOptionPane.WARNING_MESSAGE, null);
		}
	}

	/**
	 * Reads the value of an element, or empty String if no value.
	 */
	private String getTagValue(String pstrTag, Element pobjElement) {
		NodeList objNodeList = pobjElement.getElementsByTagName(pstrTag).item(0).getChildNodes();
		Node objNode = objNodeList.item(0);
		if (objNode == null || objNode.getNodeValue().equals("null"))
			return "";
		return objNode.getNodeValue();
	}
	
}
